package com.inspectortime.webapp.inspector.fee;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.axis.utils.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.validation.BindException;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;

import com.inspectortime.domain.InspectorCompany;
import com.inspectortime.domain.pricing.BaseFeeWithAdjustersCalculator;
import com.inspectortime.domain.pricing.FeeCalculator;
import com.inspectortime.domain.pricing.PricingPlanType;
import com.inspectortime.domain.type.FoundationType;
import com.inspectortime.domain.type.PropertyType;
import com.inspectortime.domain.type.State;
import com.inspectortime.repository.Factory;
import com.inspectortime.repository.Repository;
import com.inspectortime.util.SpringValidatorUtils;
import com.inspectortime.webapp.util.FlexibleNumberPropertyEditor;
import com.inspectortime.webapp.util.HttpSessionUtils;

public class BaseFeeWithAdjustersCalculatorFormController extends
		SimpleFormController {

	private static Log log = LogFactory
			.getLog(BaseFeeWithAdjustersCalculatorFormController.class);
	private Repository repository;
	private Factory factory;

	public void setRepository(Repository repository) {
		this.repository = repository;
	}

	public void setFactory(Factory repository) {
		this.factory = repository;
	}

	protected Map referenceData(HttpServletRequest request) throws Exception {
		Map<String, Object> data = new HashMap<String, Object>();
		data.put("states", State.values());
		data.put("foundationTypes", FoundationType.values());
		data.put("propertyTypes", PropertyType.values());

		int[] dollarRoundingValues = new int[] { 0, 5, 10 };
		data.put("dollarRoundingValues", dollarRoundingValues);

		int[] perBedroomIncreaseLimitValues = new int[] { 0, 2, 3, 4, 5, 6, 7,
				8, 9 };
		data
				.put("perBedroomIncreaseLimitValues",
						perBedroomIncreaseLimitValues);

		double[] perBathroomIncreaseLimitValues = new double[] { 0, 1.5, 2,
				2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6, 6.5, 7, 7.5, 8, 8.5, 9 };
		data.put("perBathroomIncreaseLimitValues",
				perBathroomIncreaseLimitValues);

		return data;
	}

	protected Object formBackingObject(HttpServletRequest request)
			throws Exception {

		String id = request.getParameter("id");
		BaseFeeWithAdjustersCalculator calculator = null;
		if (StringUtils.isEmpty(id)) {
			calculator = factory.createBaseFeeWithAdjustersCalculator();
			InspectorCompany company = HttpSessionUtils
					.retrieveLoggedInCompany(request, repository);
			calculator.setInspectorCompany(company);
		} else {
			calculator = repository.loadBaseFeeWithAdjustersCalculator(id);
		}

		// Set default center zip code to company's zip code
		if (calculator.getDistanceInMilesCenterZip() == null
				|| calculator.getDistanceInMilesCenterZip().length() < 3) {
			calculator.setDistanceInMilesCenterZip(calculator
					.getInspectorCompany().getAddress().getZipCode());
		}

		return calculator;
	}

	public static int nextSequentialFeeCalculatorId(InspectorCompany company) {
		int max = 0;
		for (FeeCalculator calculator : company.getFeeCalculators()) {
			if (calculator.getSequentialId() > max) {
				max = calculator.getSequentialId();
			}
		}
		return max + 1;
	}

	protected ModelAndView onSubmit(HttpServletRequest request,
			HttpServletResponse response, Object command, BindException errors)
			throws Exception {

		BaseFeeWithAdjustersCalculator calculator = (BaseFeeWithAdjustersCalculator) command;

		InspectorCompany company = HttpSessionUtils.retrieveLoggedInCompany(
				request, repository);

		if (StringUtils.isEmpty((String) calculator.getId())) {

			// Ensure that we have a unique local reference (used in error
			// messages, etc)
			calculator.setSequentialId(this
					.nextSequentialFeeCalculatorId(company));
			company.getFeeCalculators().add(calculator);
			calculator.setInspectorCompany(company);
		}
		calculator.save();

		// NOte: The fact that someone is saving a rule here automatically means
		// they will be switched to the Advanced plan
		company.setPricingPlanType(PricingPlanType.Advanced);
		company.save();
		ModelAndView mv = new ModelAndView(this.getSuccessView());
		return mv;
	}

	protected void onBind(HttpServletRequest request, Object command,
			BindException errors) throws Exception {
		BaseFeeWithAdjustersCalculator calculator = (BaseFeeWithAdjustersCalculator) command;

		String maxListedPrice = request
				.getParameter("calculator.maxListedPrice");
		if (maxListedPrice != null && maxListedPrice.equals("NO LIMIT")) {
			calculator.setMaxListedPrice(0);
		}

		String maxSquareFeet = request.getParameter("calculator.maxSquareFeet");
		if (maxSquareFeet != null && maxSquareFeet.equals("NO LIMIT")) {
			calculator.setMaxSquareFeet(0);
		}

		String maxNumberOfBedrooms = request
				.getParameter("calculator.maxNumberOfBedrooms");
		if (maxNumberOfBedrooms != null
				&& maxNumberOfBedrooms.equals("NO LIMIT")) {
			calculator.setMaxNumberOfBedrooms(0);
		}

		String maxNumberOfBathrooms = request
				.getParameter("calculator.maxNumberOfBathrooms");
		if (maxNumberOfBathrooms != null
				&& maxNumberOfBathrooms.equals("NO LIMIT")) {
			calculator.setMaxNumberOfBathrooms(0);
		}
	}
	
	protected void initBinder(HttpServletRequest request,
			ServletRequestDataBinder binder) throws Exception {
		binder.registerCustomEditor(Float.class, "maxListedPrice",
				new FlexibleNumberPropertyEditor("###,###,##0", Float.class, new String[] { "", "NO LIMIT" }));
		binder.registerCustomEditor(Integer.class, "maxNumberOfBedrooms",
				new FlexibleNumberPropertyEditor("###,###,##0", Integer.class, new String[] { "", "NO LIMIT" }));
		binder.registerCustomEditor(Float.class, "maxNumberOfBathrooms",
				new FlexibleNumberPropertyEditor("###,###,##0", Float.class, new String[] { "", "NO LIMIT" }));
		binder.registerCustomEditor(Double.class, "maxSquareFeet",
				new FlexibleNumberPropertyEditor("###,###,##0", Double.class, new String[] { "", "NO LIMIT" }));
	}

	protected void onBindAndValidate(HttpServletRequest request,
			Object command, BindException errors) throws Exception {
		SpringValidatorUtils.logValidationErrors(log, errors);
	}

}
